/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package clientermi;

/**
 *
 * @author hfuentes
 */
public class Operaciones {
    /*
     * Atributos de la Clase
     */
    public double[][] x; //matriz de datos de entrenamiento
    public double[] z;   //vector de salidas z
    public int col;      //numero de columnas de matriz
    public int fil;      //numero de filas de matriz
    public double c;     //valor inicial


    /*
     * Listado de Operadores Geneticos
     */

    /*
     * Cruzamiento
     */
    public double[] cruzar(double[] k_1, double[] k_2){
        //obtener un pivote de corte
        int pivote = aleatorio(0, k_1.length) - 1;
        double[] resultado = new double[k_1.length];
        if (aleatorio(0, 3) == 1) {
            for (int i = 0; i < k_1.length; i++) {
                if (i >= pivote) {
                    //pasado el punto pivote
                    resultado[i] = k_1[i];
                }
                else
                {
                    //mientra no se llege al pivote
                    resultado[i] = k_2[i];
                }
            }
        }
        else
        {
            for (int i = 0; i < k_1.length; i++) {
                if (i >= pivote) {
                    //pasado el punto pivote
                    resultado[i] = k_2[i];
                }
                else
                {
                    //mientra no se llege al pivote
                    resultado[i] = k_1[i];
                }
            }
        }
        return resultado;
    }
    

    /*
     * Mutacion
     */
    public double[] mutar(double[] k){
        int i = aleatorio(0, k.length) - 1;
        if (Math.random() < 0.5) {
            k[i] = Math.random() / k[i];
        }
        else {
            k[i] = Math.random() * k[i];
        }
        return k;
    }

    /*
     * Seleccion
     */

    /*
     * Funcion de aptitud Fitness
     *
     * Evaluacion de la calidad de una solucion con respecto al optimo esperado
     * la funcion fitness se encarga de realizar calificacion de los individuos
     * con mejores caracteristicas (funciones con menor error)
     *
     * la especificacion del funcionamiento de la funcion fitness queda
     * especificada en el pasado informe, en la seccion de solucion.
     */

    public double fitness(double[] k){
        //calcular error cuadratico medio de la solucion de coefientes propuesta (k_i)

        //sumatoria interna (1->n), de evaluacion en fila menos optimo (z)
        double sumatoria = 0;
        for (int i = 0; i < this.fil; i++)
        {//recorro las filas

            //por cada fila del conjunto de entrenamiento realizo
            //eval = c + f(x_i0, k_0) + f(x_i1, k_1) + f(x_i2, k_2) + ... + f(x_ip, k_p) /p=col
            double eval = this.c;
            for (int j = 0; j < this.col; j++)
            {//recorro las columnas
                eval += f(this.x[i][j], k[j]);
            }

            //luego: eval(i) - z(i) al cuadrado
            sumatoria = (eval - this.z[i]) * (eval - this.z[i]);
        }
        //raiz de sumatoria divido por n(n-1) (ver convencion n)
        return Math.sqrt((sumatoria)/(this.fil*(this.fil-1)));
    }
    
    //funciones privadas de la clase
    private static int aleatorio(int max,int min){
        return (int)(Math.random()*(max-min))+min;
    }
    private double f(double x, double k){
        //calcular tangente hiperbolica de cubo de x_i
        double tanh_x3 = Math.tanh(x * x * x);

        //calcular expresion f(x) especificada en el informe
        double resultado = k * tanh_x3 - k;
        return resultado;
    }
}
